# # 爬虫.
# # 1 简单认识一下requests模块
# # 第一步: 爬取服务端的文件(IO阻塞).
# # 第二步: 拿到文件,进行数据分析,(非IO,IO极少)
# import requests
# from concurrent.futures import ProcessPoolExecutor
# from multiprocessing import Process
# import time
# import random
# import os
#
# def get(url):
#     response = requests.get(url)
#     print(f'{os.getpid()} 正在爬取:{url}')
#     time.sleep(random.randint(1,3))
#     if response.status_code == 200:
#         return response.text
#
#
# def parse(text):
#     '''
#     对爬取回来的字符串的分析
#     简单用len模拟一下.
#     :param text:
#     :return:
#     '''
#     print(f'{os.getpid()} 分析结果:{len(text)}')
#
# # get('http://www.taobao.com')
# # get('http://www.baidu.com')
# # get('http://www.JD.com')
#
# if __name__ == '__main__':
#
#     url_list = [
#         'http://www.taobao.com',
#         'http://www.JD.com',
#         'http://www.JD.com',
#         'http://www.JD.com',
#         'http://www.baidu.com',
#         'https://www.cnblogs.com/jin-xin/articles/11232151.html',
#         'https://www.cnblogs.com/jin-xin/articles/10078845.html',
#         'http://www.sina.com.cn',
#         'https://www.sohu.com',
#         'https://www.youku.com',
#     ]
#     pool = ProcessPoolExecutor(4)
#     obj_list = []
#     for url in url_list:
#         obj = pool.submit(get, url)
#         obj_list.append(obj)
#
#     pool.shutdown(wait=True)
#
#     for obj in obj_list:
#         parse(obj.result())
'''
    串行
    obj_list[0].result()
    obj_list[1].result()
    obj_list[2].result()
    obj_list[3].result()
    obj_list[4].result()
'''

# 问题出在哪里?
# 1. 分析结果的过程是串行,效率低.
# 2. 你将所有的结果全部都爬取成功之后,放在一个列表中,分析.
# 问题1解决:
# 在开进程池,再开进程,耗费资源.

'''
爬取一个网页需要2s,并发爬取10个网页:2.多s.
分析任务: 1s.    10s. 总共12.多秒.

现在这个版本的过程:
    异步发出10个爬取网页的任务,然后4个进程并发(并行)的先去完成4个爬取网页的任务,然后谁先结束,谁进行下一个
    爬取任务,直至10个任务全部爬取成功.
    将10个爬取结果放在一个列表中,串行的分析.
    
爬取一个网页需要2s,分析任务: 1s,总共3s,总共3.多秒(开启进程损耗).
.    10s.
下一个版本的过程:
    异步发出10个 爬取网页+分析 的任务,然后4个进程并发(并行)的先去完成4个爬取网页+分析 的任务,
    然后谁先结束,谁进行下一个 爬取+分析 任务,直至10个爬取+分析 任务全部完成成功.

    


'''

# 版本二:
# 异步处理: 获取结果的第二种方式: 完成一个任务返回一个结果,完成一个任务,返回一个结果 并发的返回.

# import requests
# from concurrent.futures import ProcessPoolExecutor
# from multiprocessing import Process
# import time
# import random
# import os
#
# def get(url):
#     response = requests.get(url)
#     print(f'{os.getpid()} 正在爬取:{url}')
#     time.sleep(random.randint(1,3))
#     if response.status_code == 200:
#         parse(response.text)
#
#
# def parse(text):
#     '''
#     对爬取回来的字符串的分析
#     简单用len模拟一下.
#     :param text:
#     :return:
#     '''
#     print(f'{os.getpid()} 分析结果:{len(text)}')
#
# if __name__ == '__main__':
#
#     url_list = [
#         'http://www.taobao.com',
#         'http://www.JD.com',
#         'http://www.JD.com',
#         'http://www.JD.com',
#         'http://www.baidu.com',
#         'https://www.cnblogs.com/jin-xin/articles/11232151.html',
#         'https://www.cnblogs.com/jin-xin/articles/10078845.html',
#         'http://www.sina.com.cn',
#         'https://www.sohu.com',
#         'https://www.youku.com',
#     ]
#     pool = ProcessPoolExecutor(4)
#     for url in url_list:
#         obj = pool.submit(get, url)
#
#     # pool.shutdown(wait=True)
#     print('主')


# 版本三: 版本二几乎完美,但是两个任务有耦合性. 再上一个基础上,对其进程解耦.
# 回调函数

# import requests
# from concurrent.futures import ProcessPoolExecutor
# from multiprocessing import Process
# import time
# import random
# import os
#
# def get(url):
#     response = requests.get(url)
#     print(f'{os.getpid()} 正在爬取:{url}')
#     # time.sleep(random.randint(1,3))
#     if response.status_code == 200:
#         return response.text
#
#
# def parse(obj):
#     '''
#     对爬取回来的字符串的分析
#     简单用len模拟一下.
#     :param text:
#     :return:
#     '''
#     time.sleep(1)
#     print(f'{os.getpid()} 分析结果:{len(obj.result())}')
#
# if __name__ == '__main__':
#
#     url_list = [
#         'http://www.taobao.com',
#         'http://www.JD.com',
#         'http://www.JD.com',
#         'http://www.JD.com',
#         'http://www.baidu.com',
#         'https://www.cnblogs.com/jin-xin/articles/11232151.html',
#         'https://www.cnblogs.com/jin-xin/articles/10078845.html',
#         'http://www.sina.com.cn',
#         'https://www.sohu.com',
#         'https://www.youku.com',
#     ]
#     start_time = time.time()
#     pool = ProcessPoolExecutor(4)
#     for url in url_list:
#         obj = pool.submit(get, url)
#         obj.add_done_callback(parse)  # 增加一个回调函数
#         # 现在的进程完成的还是网络爬取的任务,拿到了返回值之后,结果丢给回调函数add_done_callback,
#         # 回调函数帮助你分析结果
#         # 进程继续完成下一个任务.
#     pool.shutdown(wait=True)
#
#     print(f'主: {time.time() - start_time}')

# 回调函数是主进程帮助你实现的, 回调函数帮你进行分析任务. 明确了进程的任务: 只有一个网络爬取.
# 分析任务: 回调函数执行了.对函数之间解耦.

# 极值情况: 如果回调函数是IO任务,那么由于你的回调函数是主进程做的,所以有可能影响效率.

# 回调不是万能的,如果回调的任务是IO,
# 那么异步 + 回调机制 不好.此时如果你要效率只能牺牲开销,再开一个线程进程池.


# 异步就是回调! 这个是错的!! 异步,回调是两个概念.

# 如果多个任务,多进程多线程处理的IO任务.
# 1. 剩下的任务 非IO阻塞.  异步 + 回调机制
# 2. 剩下的任务 IO << 多个任务的IO  异步 + 回调机制
# 3. 剩下的任务 IO >= 多个任务的IO  第二种解决方式,或者两个进程线程池.